﻿using IronPython.Runtime;
using Microsoft.EntityFrameworkCore;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoreLims.Models.CoreLims
{
    using Sample = SampleSample;

    public static class SampleSampleExtension
    {
        public static Sample getSampleLogin(this Sample sample, CoreLimsContext dbContext, string Id) =>
            dbContext.Sample.FirstOrDefault(s => s.Id == Id);

        /// <summary>
        /// 根据系统生成的样品ID，查找相应的未完成样品。目前该函数只用于导入数据时使用
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="SampleId"></param>
        /// <returns></returns>
        public static Sample getSampleLoginBySampleId(this Sample sample, CoreLimsContext dbContext, string SampleId) =>
            dbContext.Sample.FirstOrDefault(s => s.SampleId == SampleId && s.Status != "完成");

        public static List<Sample> getSampleList(this Sample sample, CoreLimsContext dbContext) =>
            dbContext.Sample.ToList();

        /// <summary>
        /// 获得所有状态为 登录 的样品
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <returns></returns>
        public static List<Sample> getSampleLoginList(this Sample sample, CoreLimsContext dbContext) =>
            dbContext.Sample.Where(s => s.Status == SAMPLE.SampleStatus.登录.ToString()).OrderByDescending(x => x.LoginTime).ToList();

        /// <summary>
        /// 获得所有状态为 采样 的样品
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <returns></returns>
        public static List<Sample> getSamplingList(this Sample sample, CoreLimsContext dbContext) =>
            dbContext.Sample.Where(s => s.CurrentWorkFlow == "采样").OrderByDescending(x => x.LoginTime).ToList();

        /// <summary>
        /// 获得所有状态为 接收 的样品
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <returns></returns>
        public static List<Sample> getReceiveSamples(this Sample sample, CoreLimsContext dbContext, string Ids)
        {
            if (string.IsNullOrEmpty(Ids))
                return dbContext.Sample.Where(s => s.CurrentWorkFlow == "接收").OrderByDescending(x => x.LoginTime).ToList();
            else
                return dbContext.Sample.Where(s => s.CurrentWorkFlow == "接收" && Ids.Contains(s.SampleId)).OrderByDescending(x => x.LoginTime).ToList();
        }

        /// <summary>
        /// 获得所有状态为 结果录入 的样品
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids"></param>
        /// <returns></returns>
        public static List<Sample> getResultEntrySamples(this Sample sample, CoreLimsContext dbContext, string Ids)
        {
            if (string.IsNullOrEmpty(Ids))
                return dbContext.Sample.Where(s => s.CurrentWorkFlow == "结果录入").OrderByDescending(x => x.LoginTime).ToList();
            else
                return dbContext.Sample.Where(s => s.CurrentWorkFlow == "结果录入" && Ids.Contains(s.SampleId)).OrderByDescending(x => x.LoginTime).ToList();
        }

        /// <summary>
        /// 根据 批次号 查询该批次内所有待录入结果的分析项
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="BatchId"></param>
        /// <returns></returns>
        public static List<SampleResult> getResultAnalyteByBatchid(this Sample sample, CoreLimsContext dbContext, string BatchId)
        {
            var list = dbContext.Sample.Where(s => s.BatchId == BatchId && s.CurrentWorkFlow == "结果录入")
                .Select(s => new { s.Id })
                .ToArray();

            string[] array = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                array[i] = list[i].Id;
            }

            return dbContext.Result.Where(s => array.Contains(s.SampleId) && s.Final == null).ToList();
        }

        /// <summary>
        /// 根据指定的流程步骤名称，获取对应的所有样品
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="StepName"></param>
        /// <returns></returns>
        public static List<Sample> getSamplesByStepName(this Sample sample, CoreLimsContext dbContext, string StepName)
        {
            if (string.IsNullOrEmpty(StepName))
                return new List<Sample>();
            else
                return dbContext.Sample.Where(s => s.CurrentWorkFlow == StepName).OrderByDescending(x => x.LoginTime).ToList();
        }

        public static List<Sample> getSamplesByStepName(this Sample sample, CoreLimsContext dbContext, string StepName, string BatchId)
        {
            if (string.IsNullOrEmpty(StepName))
                return new List<Sample>();
            else
                return dbContext.Sample.Where(s => s.CurrentWorkFlow == StepName && s.BatchId == BatchId).OrderBy(x => x.SampleId).ToList();
        }

        /// <summary>
        /// 登录一个或多个样品
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="SampleDefinitionList"></param>
        /// <returns></returns>
        public async static Task<string> AddSampleDefinition(this Sample sample, CoreLimsContext dbContext, string SampleDefinitionList, string BatchId, CommonUser user)
        {
            var sdList = SampleDefinitionList.Split(',');
            string SampleDefinitionId = "";
            string SampleDefinitionName = "";

            try
            {
                foreach (var item in sdList)
                {
                    SampleDefinitionId = item.Split('.')[0];
                    var number = 1;
                    int.TryParse(item.Split('.')[1], out number);
                    for (int i = 1; i <= number; i++)
                    {
                        var relist = new List<SampleLoginRelation>();
                        var sd = SAMPLE.SampleDefinition.getSampleDefinition(dbContext, SampleDefinitionId); // 获得 样品定义
                        SampleDefinitionId = sd.Id; // 如果插入样品出错，这个样品定义ID会被记录到日志中。
                        SampleDefinitionName = sd.Name;

                        var analytesList = sd.getRelationAnalytes(dbContext, sd.Id);  // 获得跟 sd 直接关联的分析项列表
                        var testDefinitionList = sd.getRelationTestDefinition(dbContext, sd.Id);  // 获得跟 sd 关联的测试列表
                        var specCollectionList = sd.getRelationSpecCollection(dbContext, sd.Id);  // 获得样品定义直接关联的指标集

                        var newSampleLogin = NewSample(sd);
                        newSampleLogin.LoginPersonId = user.Id;
                        newSampleLogin.LoginPersonName = user.FullName;
                        newSampleLogin.BatchId = BatchId;

                        newSampleLogin.RetentionConfigId = sd.RetentionConfigId;
                        dbContext.Add(newSampleLogin);

                        NewSampleDefinitionAnalytes(analytesList, relist, newSampleLogin.Id);
                        NewTestDefinitionAndAnalytes(dbContext, testDefinitionList, relist, newSampleLogin.Id);
                        NewSampleSpecCollection(specCollectionList, relist, newSampleLogin.Id);

                        foreach (var re in relist)
                            dbContext.Add(re);
                    }
                }

                await dbContext.SaveChangesAsync();
                return "样品添加成功！";
            }
            catch (Exception ex)
            {
                var ruser = Common.User.getUserByIdentityName(dbContext, "admin");
                var audit = Audit.newAudit;
                audit.EventName = "登录样品";
                audit.TableName = "样品名称：" + SampleDefinitionName;
                audit.RecordId = SampleDefinitionId;
                audit.RemindUserId = ruser.Id;
                audit.RemindUserName = ruser.FullName;
                audit.Explain = ex.Message.Substring(0, ex.Message.Length > 1000 ? 1000 : ex.Message.Length); ;
                dbContext.Add(audit);
                await dbContext.SaveChangesAsync();
                
                return "样品登录失败！该信息已被系统记录，请联系管理员。";
            }
        }

        /// <summary>
        /// 添加登录样品包含的测试
        /// </summary>
        /// <param name="lr"></param>
        /// <param name="dbContext"></param>
        /// <param name="SampleLoginId"></param>
        /// <param name="TestDefinitionId"></param>
        /// <returns></returns>
        public static string AddSampleLoginTestDefinition(this Sample sample, CoreLimsContext dbContext, string SampleLoginId, string TestDefinitionId)
        {
            var rel = dbContext.LoginRelation.FirstOrDefault(s => s.SampleId == SampleLoginId && s.TestId == TestDefinitionId);

            if (rel != null)
                return "样品已经包含该测试！";

            var relist = new List<SampleLoginRelation>();
            NewTestDefinitionRelation(dbContext, TestDefinitionId, relist, SampleLoginId);

            foreach (var re in relist)
                dbContext.Add(re);

            dbContext.SaveChanges();
            return "样品包含的测试添加成功！";
        }

        /// <summary>
        /// 获取样品定义中关联的测试，将测试及包含的分析项关系复制到登录样品关系表中
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="sdId"></param>
        /// <param name="newSampleLogin"></param>
        private static void NewTestDefinitionAndAnalytes(CoreLimsContext dbContext, IQueryable<object> testDefinitionList, List<SampleLoginRelation> relist, string newSampleLoginId)
        {
            foreach (var test in testDefinitionList)
            {
                int count = relist.Count;
                var lg = new SampleLoginRelation();
                lg.Id = SAMPLE._newId();
                lg.SampleId = newSampleLoginId;
                lg.TestId = test.GetType().GetProperty("IncludedId").GetValue(test).ToString();

                int a = 1;
                int.TryParse(test.GetType().GetProperty("Repeat").GetValue(test).ToString(), out a);
                lg.DetectionTimes = a;

                var ConnectionString = dbContext.Database.GetConnectionString();
                var _dbContext = new CoreLimsContext(ConnectionString);
                var testDefinition = SAMPLE.TestDefinition.getTestDefinition(_dbContext, lg.TestId);

                AddAnalyteToRelation(relist, newSampleLoginId, lg, _dbContext, testDefinition);
                if (relist.Count > count)  // 如果测试包含分析项并且已经添加则添加该测试，否则不添加该测试
                {
                    relist.Add(lg); // 在添加测试的基础上，再查找测试关联的 指标集 和 方法，并添加到登录样品关系表中
                    AddSpecCollectionToRelation(relist, newSampleLoginId, _dbContext, testDefinition);
                    AddMethodToRelation(relist, newSampleLoginId, _dbContext, testDefinition);
                }
            }
        }

        /// <summary>
        /// 将测试中的所有关系复制到登陆样品关系表中
        /// </summary>
        /// <param name="TestDefinitionId"></param>
        /// <param name="relist"></param>
        /// <param name="newSampleLoginId"></param>
        private static void NewTestDefinitionRelation(CoreLimsContext dbContext, string TestDefinitionId, List<SampleLoginRelation> relist, string newSampleLoginId)
        {
            int count = relist.Count;
            var lg = new SampleLoginRelation();
            lg.Id = SAMPLE._newId();
            lg.SampleId = newSampleLoginId;
            lg.TestId = TestDefinitionId;
            lg.DetectionTimes = 1;

            var ConnectionString = dbContext.Database.GetConnectionString();
            var _dbContext = new CoreLimsContext(ConnectionString);
            var testDefinition = SAMPLE.TestDefinition.getTestDefinition(dbContext, lg.TestId);

            AddAnalyteToRelation(relist, newSampleLoginId, lg, _dbContext, testDefinition);
            if (relist.Count > count)  // 如果测试包含分析项并且已经添加则添加该测试，否则不添加该测试
            {
                relist.Add(lg); // 在添加测试的基础上，再查找测试关联的 指标集 和 方法，并添加到登录样品关系表中
                AddSpecCollectionToRelation(relist, newSampleLoginId, _dbContext, testDefinition);
                AddMethodToRelation(relist, newSampleLoginId, _dbContext, testDefinition);
            }
        }

        /// <summary>
        /// 将测试关联的分析项复制到关系表中
        /// </summary>
        /// <param name="relist"></param>
        /// <param name="newSampleLoginId"></param>
        /// <param name="lg"></param>
        /// <param name="_dbContext"></param>
        /// <param name="testDefinition"></param>
        private static void AddAnalyteToRelation(List<SampleLoginRelation> relist, string newSampleLoginId, SampleLoginRelation lg, CoreLimsContext _dbContext, SampleTestDefinition testDefinition)
        {
            var anaList = testDefinition.getTestDefinitionRelationAnalytes(_dbContext);
            foreach (var ana in anaList)
            {
                var lga = new SampleLoginRelation();
                lga.Id = SAMPLE._newId();
                lga.SampleId = newSampleLoginId;
                lga.TestId = lg.TestId;
                lga.AnalyteId = ana.GetType().GetProperty("AnalytesId").GetValue(ana).ToString();

                int b = 1;
                int.TryParse(ana.GetType().GetProperty("DetectionTimes").GetValue(ana).ToString(), out b);
                lga.DetectionTimes = b;
                relist.Add(lga);
            }
        }

        /// <summary>
        /// 将测试关联的指标集复制到关系表中
        /// </summary>
        /// <param name="relist"></param>
        /// <param name="newSampleLoginId"></param>
        /// <param name="_dbContext"></param>
        /// <param name="testDefinition"></param>
        private static void AddSpecCollectionToRelation(List<SampleLoginRelation> relist, string newSampleLoginId, CoreLimsContext _dbContext, SampleTestDefinition testDefinition)
        {
            var scList = testDefinition.getTestDefinitionRelationSpecCollection(_dbContext);  // 获得测试关联的指标集
            foreach (var sc in scList)
            {
                var lsc = new SampleLoginRelation();
                lsc.Id = SAMPLE._newId();
                lsc.SampleId = newSampleLoginId;
                lsc.TestId = testDefinition.Id;
                lsc.SpecCollectionId = sc.GetType().GetProperty("SpecCollectionId").GetValue(sc).ToString();
                var isdefault = sc.GetType().GetProperty("IsDefault").GetValue(sc);
                if (isdefault == null)
                    lsc.IsDefault = false;
                else
                {
                    if (isdefault.ToString() == "True")
                        lsc.IsDefault = true;
                    else
                        lsc.IsDefault = false;
                }
                lsc.DetectionTimes = 1;
                relist.Add(lsc);
            }
        }

        /// <summary>
        /// 将测试关联的方法复制到关系表中
        /// </summary>
        /// <param name="relist"></param>
        /// <param name="newSampleLoginId"></param>
        /// <param name="_dbContext"></param>
        /// <param name="testDefinition"></param>
        private static void AddMethodToRelation(List<SampleLoginRelation> relist, string newSampleLoginId, CoreLimsContext _dbContext, SampleTestDefinition testDefinition)
        {
            var meList = testDefinition.getTestDefinitionRelationMethod(_dbContext);
            foreach (var me in meList)
            {
                var lme = new SampleLoginRelation();
                lme.Id = SAMPLE._newId();
                lme.SampleId = newSampleLoginId;
                lme.TestId = testDefinition.Id;
                lme.MethodId = me.GetType().GetProperty("MethodId").GetValue(me).ToString();
                lme.DetectionTimes = 1;

                var isdefault = me.GetType().GetProperty("IsDefault").GetValue(me);
                if (isdefault == null || isdefault.ToString() == "False")
                    lme.IsDefault = false;
                else
                    lme.IsDefault = true;

                relist.Add(lme);
            }
        }

        /// <summary>
        /// 根据样品定义中直接关联的分析项，生成登录样品关联的分析项
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="sd"></param>
        /// <param name="newSampleLogin"></param>
        /// <returns></returns>
        private static void NewSampleDefinitionAnalytes(IQueryable<object> analytesList, List<SampleLoginRelation> relist, string newSampleLoginId)
        {
            foreach (var rel in analytesList)
            {
                var lg = new SampleLoginRelation();
                lg.Id = SAMPLE._newId();
                lg.SampleId = newSampleLoginId;
                lg.AnalyteId = rel.GetType().GetProperty("IncludedId").GetValue(rel).ToString();

                int a = 1;
                int.TryParse(rel.GetType().GetProperty("Repeat").GetValue(rel).ToString(), out a);
                lg.DetectionTimes = a;
                relist.Add(lg);
            }
        }

        /// <summary>
        /// 根据样品定义中直接关联的指标集，生成登录样品关联的指标集
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="sd"></param>
        /// <param name="newSampleLogin"></param>
        /// <returns></returns>
        private static void NewSampleSpecCollection(IQueryable<object> specCollectionList, List<SampleLoginRelation> relist, string newSampleLoginId)
        {
            foreach (var rel in specCollectionList)
            {
                var lg = new SampleLoginRelation();
                lg.Id = SAMPLE._newId();
                lg.SampleId = newSampleLoginId;
                lg.DetectionTimes = 1;
                lg.SpecCollectionId = rel.GetType().GetProperty("IncludedId").GetValue(rel).ToString();

                var def = rel.GetType().GetProperty("Repeat").GetValue(rel) == null? null: rel.GetType().GetProperty("Repeat").GetValue(rel).ToString();
                if (def == "1")
                    lg.IsDefault = true;
                else
                    lg.IsDefault = false;

                relist.Add(lg);
            }
        }

        /// <summary>
        /// 根据 样品定义，生成一个登录样品
        /// </summary>
        /// <param name="sd"></param>
        /// <returns></returns>
        private static Sample NewSample(SampleSampleDefinition sd)
        {
            Sample sp = new Sample();

            sp.Id = SAMPLE._newId();
            sp.Name = sd.Name;
            sp.SampleNumber = sd.DefaultNumber;
            sp.Description = sd.Description;
            sp.Classification = sd.Classification;
            sp.GenricClass = sd.GenricClass;
            sp.Site = sd.Site;
            sp.Group = sd.Group;
            sp.LoginTime = DateTime.Now;
            sp.LoginPersonId = "xxx-personid";
            sp.LoginPersonName = "System";
            sp.WorkFlowId = sd.WorkFlowId;
            sp.SamplingPoint = sd.SamplingPoint;
            sp.MaterialId = sd.MaterialId;
            sp.SkipSequence = sd.SkipSequence;
            sp.ReportName = sd.ReportName;
            sp.Status = SAMPLE.SampleStatus.登录.ToString();
            sp.IsRetention = sd.IsRetention;
            sp.IsRelease = sd.IsRelease;

            return sp;
        }

        /// <summary>
        /// 更新批次号
        /// </summary>
        /// <param name="tal"></param>
        /// <param name="dbContext"></param>
        /// <param name="Id"></param>
        /// <param name="AcceptanceRules"></param>
        /// <returns></returns>
        public static string UpdateSampleLoginBatchId(this Sample sample, CoreLimsContext dbContext, string Id, string BatchId)
        {
            Sample sp = SAMPLE.Sample.getSampleLogin(dbContext, Id);
            sp.BatchId = BatchId.Substring(0, BatchId.Length > 50 ? 50 : BatchId.Length);

            dbContext.Update(sp);
            dbContext.SaveChanges();
            return "更新成功！";
        }

        /// <summary>
        /// 更新样品编号
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Id"></param>
        /// <param name="SampleNumber"></param>
        /// <returns></returns>
        public static string UpdateSampleLoginSampleNumber(this Sample sample, CoreLimsContext dbContext, string Id, string SampleNumber)
        {
            Sample sp = SAMPLE.Sample.getSampleLogin(dbContext, Id);
            sp.SampleNumber = SampleNumber.Substring(0, SampleNumber.Length > 50 ? 50 : SampleNumber.Length);

            dbContext.Update(sp);
            dbContext.SaveChanges();
            return "更新成功！";
        }

        /// <summary>
        /// 更新检测次数
        /// </summary>
        /// <param name="tal"></param>
        /// <param name="dbContext"></param>
        /// <param name="Id"></param>
        /// <param name="AcceptanceRules"></param>
        /// <returns></returns>
        public static string UpdateSampleLoginDetectionTimes(this Sample sample, CoreLimsContext dbContext, string Id, string DetectionTimes)
        {
            int count = 0;
            int.TryParse(DetectionTimes, out count);

            if (count <= 0)
                return "检测次数必须是大于零的整数！";

            var lr = SAMPLE.LoginRelation.getLoginRelation(dbContext, Id);
            lr.DetectionTimes = count;

            dbContext.Update(lr);
            dbContext.SaveChanges();
            return "更新成功！";
        }

        /// <summary>
        /// 更新样品指派人
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Id"></param>
        /// <param name="PersonId"></param>
        /// <param name="PersonName"></param>
        /// <returns></returns>
        public static string UpdateSampleLoginAssignPerson(this Sample sample, CoreLimsContext dbContext, string Id, string PersonId, string PersonName)
        {
            var sp = SAMPLE.Sample.getSampleLogin(dbContext, Id);
            sp.AssignPersonId = PersonId;
            sp.AssignPersonName = PersonName;

            dbContext.Update(sp);
            dbContext.SaveChanges();
            return "更新成功！";
        }

        /// <summary>
        /// 更新样品指派组
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Id"></param>
        /// <param name="GroupId"></param>
        /// <param name="GroupName"></param>
        /// <returns></returns>
        public static string UpdateSampleLoginAssignGroup(this Sample sample, CoreLimsContext dbContext, string Id, string GroupId, string GroupName)
        {
            var sp = SAMPLE.Sample.getSampleLogin(dbContext, Id);
            sp.AssignGroupId = GroupId;
            sp.AssignGroupName = GroupName;

            dbContext.Update(sp);
            dbContext.SaveChanges();
            return "更新成功！";
        }

        /// <summary>
        /// 更新流程跳过步骤
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Id"></param>
        /// <param name="SkipSequence"></param>
        /// <returns></returns>
        public static string UpdateSkipSequence(this Sample sample, CoreLimsContext dbContext, string Id, string SkipSequence)
        {
            var sl = SAMPLE.Sample.getSampleLogin(dbContext, Id);
            sl.SkipSequence = SkipSequence;

            dbContext.Update(sl);
            dbContext.SaveChanges();
            return "流程步骤更新成功！";
        }

        /// <summary>
        /// 获取跟登录样品直接关联的分析项
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbcontext"></param>
        /// <param name="SampleId"></param>
        /// <returns></returns>
        public static IQueryable<object> getRelationAnalytes(this Sample sample, CoreLimsContext dbcontext, string SampleId)
        {
            var list = dbcontext.LoginRelation.Where(s => s.SampleId == SampleId && s.TestId == null)
                .Select(s => new { s.AnalyteId })
                .ToArray();

            string[] array = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                array[i] = list[i].AnalyteId;
            }

            var analist = from analyte in dbcontext.Analyte
                          join relation in dbcontext.LoginRelation on analyte.Id equals relation.AnalyteId
                          where (array.Contains(analyte.Id) && relation.TestId == null && relation.SampleId == SampleId)
                          orderby(analyte.Code)
                          select new
                          {
                              relation.Id,
                              analyte.Code,
                              analyte.Name,
                              analyte.Classification,
                              analyte.Description,
                              analyte.ResultModel,
                              analyte.RoundingOff,
                              analyte.Units,
                              analyte.DefaultSpecName,
                              analyte.Assist,
                              relation.DetectionTimes,
                          };

            return analist;
        }

        /// <summary>
        /// 获取跟登录样品关联的测试
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbcontext"></param>
        /// <param name="SampleId"></param>
        /// <returns></returns>
        public static IQueryable<object> getRelationTestDefinition(this Sample sample, CoreLimsContext dbcontext, string SampleId)
        {
            var list = dbcontext.LoginRelation.Where(s => s.SampleId == SampleId && s.AnalyteId == null 
                    && s.SpecCollectionId == null && s.MethodId == null)
                .Select(s => new { s.TestId })
                .ToArray();

            string[] array = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                array[i] = list[i].TestId;
            }

            var tdlist = from tdf in dbcontext.TestDefinition
                         join relation in dbcontext.LoginRelation on tdf.Id equals relation.TestId
                         where (array.Contains(tdf.Id) && relation.SampleId == SampleId 
                            && relation.AnalyteId == null && relation.SpecCollectionId == null && relation.MethodId == null)
                         select new
                         {
                             relation.Id,
                             tdf.TestName,
                             tdf.FirstGroup,
                             tdf.SecondGroup,
                             tdf.Description,
                             tdf.Version,
                             relation.DetectionTimes,
                         };

            return tdlist;
        }

        /// <summary>
        /// 返回测试关联的分析项
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbcontext"></param>
        /// <param name="TestId"></param>
        /// <returns></returns>
        public static IQueryable<object> getTestRelationAnalytes(this Sample sample, CoreLimsContext dbcontext, string RelationId)
        {
            var test = SAMPLE.LoginRelation.getLoginRelation(dbcontext, RelationId);
            var list = dbcontext.LoginRelation.Where(s => s.SampleId == test.SampleId && s.TestId == test.TestId && s.AnalyteId != null)
                .Select(s => new { s.AnalyteId })
                .ToArray();

            string[] array = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                array[i] = list[i].AnalyteId;
            }

            var tdlist = from ana in dbcontext.Analyte
                         join relation in dbcontext.LoginRelation on ana.Id equals relation.AnalyteId
                         where (array.Contains(ana.Id) && relation.SampleId == test.SampleId
                            && relation.SampleId == test.SampleId && relation.TestId == test.TestId && relation.AnalyteId != null)
                         select new
                         {
                             relation.Id,
                             relation.DetectionTimes,
                             ana.Code,
                             ana.Name,
                             ana.Classification,
                             ana.Description,
                             ana.ResultModel,
                             ana.RoundingOff,
                             ana.Units,
                             ana.DefaultSpecName,
                             ana.Assist,
                         };

            return tdlist;
        }

        /// <summary>
        /// 返回测试关联的方法
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbcontext"></param>
        /// <param name="TestId"></param>
        /// <returns></returns>
        public static IQueryable<object> getTestRelationMethod(this Sample sample, CoreLimsContext dbcontext, string TestId)
        {
            var test = SAMPLE.LoginRelation.getLoginRelation(dbcontext, TestId);
            var list = dbcontext.LoginRelation.Where(s => s.SampleId == test.SampleId && s.TestId == test.TestId && s.MethodId != null)
                .Select(s => new { s.MethodId })
                .ToArray();

            string[] array = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                array[i] = list[i].MethodId;
            }

            var tdlist = from method in dbcontext.Method
                         join relation in dbcontext.LoginRelation on method.Id equals relation.MethodId
                         where (array.Contains(method.Id) && relation.SampleId == test.SampleId
                            && relation.SampleId == test.SampleId && relation.TestId == test.TestId && relation.MethodId != null)
                         select new
                         {
                             relation.Id,
                             relation.IsDefault,
                             method.Code,
                             method.Name,
                             method.Type,
                             method.Description,
                             method.EffectiveDate,
                             method.ExpireDate,
                             method.RecordSheet,
                             method.Version,
                             method.Status,
                         };

            return tdlist;
        }

        /// <summary>
        /// 返回测试关联的指标集
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbcontext"></param>
        /// <param name="TestId"></param>
        /// <returns></returns>
        public static IQueryable<object> getTestRelationSpecCollection(this Sample sample, CoreLimsContext dbcontext, string TestId)
        {
            var test = SAMPLE.LoginRelation.getLoginRelation(dbcontext, TestId);
            var list = dbcontext.LoginRelation.Where(s => s.SampleId == test.SampleId && s.TestId == test.TestId && s.SpecCollectionId != null)
                .Select(s => new { s.SpecCollectionId })
                .ToArray();

            string[] array = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                array[i] = list[i].SpecCollectionId;
            }

            var tdlist = from spec in dbcontext.Spec
                         join relation in dbcontext.LoginRelation on spec.Id equals relation.SpecCollectionId
                         where (array.Contains(spec.Id) && relation.SampleId == test.SampleId
                            && relation.SampleId == test.SampleId && relation.TestId == test.TestId && relation.SpecCollectionId != null)
                         select new
                         {
                             relation.Id,
                             relation.IsDefault,
                             spec.Code,
                             spec.Name,
                             spec.Description,
                             spec.FirstGroup,
                             spec.SecondGroup,
                             spec.Version,
                             spec.ReleaseStatus,
                             spec.Enable,
                         };

            return tdlist;
        }

        /// <summary>
        /// 获取跟登录样品直接关联的指标集
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbcontext"></param>
        /// <param name="SampleId"></param>
        /// <returns></returns>
        public static IQueryable<object> getRelationSpecCollection(this Sample sample, CoreLimsContext dbcontext, string SampleId)
        {
            var list = dbcontext.LoginRelation.Where(s => s.SampleId == SampleId && s.TestId == null
                    && s.SpecCollectionId != null)
                .Select(s => new { s.SpecCollectionId })
                .ToArray();

            string[] array = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                array[i] = list[i].SpecCollectionId;
            }

            var tdlist = from spec in dbcontext.Spec
                         join relation in dbcontext.LoginRelation on spec.Id equals relation.SpecCollectionId
                         where (array.Contains(spec.Id) && relation.SampleId == SampleId
                            && relation.TestId == null && relation.SpecCollectionId != null)
                         select new
                         {
                             relation.Id,
                             spec.Code,
                             spec.Name,
                             spec.FirstGroup,
                             spec.SecondGroup,
                             spec.Description,
                             spec.Version,
                             spec.ReleaseStatus,
                             relation.IsDefault,
                             relation.DetectionTimes,
                         };

            return tdlist;
        }

        /// <summary>
        /// 删除登录样品
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids">可以是逗号分隔的id字符串列表</param>
        /// <returns></returns>
        public async static Task<string> DeleteSampleLogin(this Sample sample, CoreLimsContext dbContext, string Ids)
        {
            var ids = Ids.Split(',');
            foreach (var id in ids)
            {
                var sl = SAMPLE.Sample.getSampleLogin(dbContext, id);

                var list = dbContext.LoginRelation.Where(s => s.SampleId == id).ToList(); // 删除关系
                foreach (var item in list)
                    dbContext.Remove(item);

                var results = SAMPLE.Result.getResults(dbContext, sl.Id); // 删除所有结果项
                foreach (var item in results)
                    dbContext.Remove(item);

                var fileList = Common.UploadFile.getIdsByDomain(dbContext, "Sample", sl.Id);
                Common.UploadFile.DeleteUploadFile(dbContext, "Sample", sl.Id); // 删除关联文件

                var retention = SAMPLE.RetentionSample.getBySampleId(dbContext, sl.Id);
                if (retention.Count > 0)
                    dbContext.Remove(retention);

                var wf = WorkFlow.RemoveRuntime(id); // 删除运行时流程
                dbContext.Remove(sl);
            }

            await dbContext.SaveChangesAsync();
            return "样品删除成功！";
        }

        /// <summary>
        /// 开始样品
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids"></param>
        /// <returns></returns>
        public static string StartSampleLogin(this Sample sample, CoreLimsContext dbContext, string Ids, string UserId, string UserName)
        {
            var ids = Ids.Split(',');

            string[] SampleNumberArrary;
            string st = getSampleNumberArrary(dbContext, ids.Length, out SampleNumberArrary);
            if (st != "成功")
                return st;

            int i = 0;
            foreach (var id in ids)
            {
                var sp = dbContext.Sample.FirstOrDefault(s => s.Id == id);
                var allList = dbContext.LoginRelation.Where(s => s.SampleId == sp.Id).ToList(); // 该样品所有的关系

                var checkst = StartCheck(dbContext, sp, allList);
                if (checkst != null)
                    return checkst;

                st = MakeResultsByAnalyte(dbContext, sp, allList);
                st = MakeResultsByTest(dbContext, sp, allList);

                var workFlow = WorkFlow.GetWorkFlow(sp.WorkFlowId);
                if (workFlow.Definition == null) { return "样品：" + sp.Name +" 不可登录，关联流程没有找到或是已删除！"; }
                workFlow.CreateRuntimeWorkFlow(sp);
                workFlow.RunWorkFlow(handlerType: UserName, handlerId: UserId);
                workFlow.SkipRunWorkFlow(sp.SkipSequence, handlerType: UserName, handlerId: UserId);

                var name = workFlow.getCurrentRunStepName();
                var nextName = workFlow.getCurrentNextRunStepName();
                sp.Status = SAMPLE.SampleStatus.检测中.ToString();
                sp.CurrentWorkFlow = name;
                sp.NextWorkFlow = nextName;
                sp.SampleId = SampleNumberArrary[i];

                dbContext.Update(sp);
                dbContext.SaveChanges();
                i++;
            }

            return st;
        }

        private static string MakeResultsByTest(CoreLimsContext dbContext, Sample sample, List<SampleLoginRelation> allList)
        {
            var testList = allList.Where(s => s.SampleId == sample.Id && s.TestId != null
                        && s.AnalyteId == null && s.SpecCollectionId == null && s.MethodId == null)
                        .ToList(); // 查询样品包含的测试

            foreach (var test in testList)
            {
                for (int testTimes = 1; testTimes <= test.DetectionTimes; testTimes++) // 循环测试的检测次数
                {
                    var anaList = allList.Where(s => s.SampleId == sample.Id && s.TestId == test.TestId
                                && s.AnalyteId != null && s.SpecCollectionId == null && s.MethodId == null).ToList(); // 测试所包含的分析项列表

                    var specCollection = allList.Where(s => s.SampleId == sample.Id && s.TestId == test.TestId
                                && s.AnalyteId == null && s.SpecCollectionId != null && s.MethodId == null && s.IsDefault == true)
                                .FirstOrDefault();  // 获得该测试的默认指标集

                    var testDefinition = SAMPLE.TestDefinition.getTestDefinition(dbContext, test.TestId); // 获得测试定义

                    var method = allList.Where(s => s.SampleId == sample.Id && s.TestId == test.TestId
                                && s.AnalyteId == null && s.SpecCollectionId == null && s.MethodId != null && s.IsDefault == true)
                                .FirstOrDefault();  // 获得该测试的默认方法ID

                    if (specCollection == null) // 测试不包含指标集
                    {
                        foreach (var ana in anaList)
                        {
                            var analy = SAMPLE.Analyte.getAnalyte(dbContext, ana.AnalyteId);
                            MakeResultByAnalyteSelf(dbContext, analy, ana, analy.DefaultSpecId, testTimes, testDefinition.Id, testDefinition.TestName, method == null ? null : method.MethodId);
                        }
                    }
                    else
                    {
                        foreach (var ana in anaList)
                        { // 检查分析项是否包含在指标集中
                            var specList = SAMPLE.Spec.getSpecCollectionAnaylte(dbContext, specCollection.SpecCollectionId, ana.AnalyteId).ToList();
                            if (specList.Count > 0)
                            {
                                var analy = SAMPLE.Analyte.getAnalyte(dbContext, ana.AnalyteId);
                                var specId = specList[0].GetType().GetProperty("Id").GetValue(specList[0]).ToString();
                                MakeResultByAnalyteSelf(dbContext, analy, ana, specId, testTimes, testDefinition.Id, testDefinition.TestName, method == null?null:method.MethodId);
                            }
                            else
                            {
                                var analy = SAMPLE.Analyte.getAnalyte(dbContext, ana.AnalyteId);
                                MakeResultByAnalyteSelf(dbContext, analy, ana, analy.DefaultSpecId, testTimes, testDefinition.Id, testDefinition.TestName, method == null ? null : method.MethodId);
                            }
                        }
                    }
                }
            }

            return "成功";
        }

        /// <summary>
        /// 根据登录样品包含的分析项，生成 Result
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="sample"></param>
        /// <param name="allList"></param>
        /// <returns></returns>
        private static string MakeResultsByAnalyte(CoreLimsContext dbContext, Sample sample, List<SampleLoginRelation> allList)
        {
            var anaList = allList.Where(s => s.SampleId == sample.Id && s.AnalyteId != null && s.TestId == null)
                        .ToList(); // 该样品直接关联的分析项

            var spec = allList.FirstOrDefault(s => s.SampleId == sample.Id 
                        && s.SpecCollectionId != null && s.TestId == null && s.IsDefault == true); // 该样品的默认指标集

            if (spec == null)
            {
                foreach (var ana in anaList)
                {
                    var analy = SAMPLE.Analyte.getAnalyte(dbContext, ana.AnalyteId);
                    MakeResultByAnalyteSelf(dbContext, analy, ana, analy.DefaultSpecId);
                }
            }
            else
            {
                foreach (var ana in anaList)
                { // 检查分析项是否包含在指标集中
                    var specList = SAMPLE.Spec.getSpecCollectionAnaylte(dbContext, spec.SpecCollectionId, ana.AnalyteId).FirstOrDefault();
                    var analy = SAMPLE.Analyte.getAnalyte(dbContext, ana.AnalyteId);
                    if (specList != null)
                    {
                        var specId = specList.GetType().GetProperty("Id").GetValue(specList).ToString();
                        MakeResultByAnalyteSelf(dbContext, analy, ana, specId);
                    }
                    else
                    {
                        MakeResultByAnalyteSelf(dbContext, analy, ana, analy.DefaultSpecId);
                    }
                }
            }
            return "成功";
        }

        /// <summary>
        /// 根据分析项自身的设置和相关指标集，生成一项 Result。
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static void MakeResultByAnalyteSelf(CoreLimsContext dbContext, SampleAnalyte analyte, SampleLoginRelation slr, string specId,
            int TestTimes = 1, string TestId=null, string TestName=null, string MethodId=null)
        {
            var spec = SAMPLE.Spec.getSpec(dbContext, specId);

            for (int i = 1; i <= slr.DetectionTimes; i++) // 测试几次就插入几条记录
            {
                var result = new SampleResult();
                result.SampleId = slr.SampleId;
                result.AnalytesId = analyte.Id;
                result.AnalytesCode = analyte.Code;
                result.AnalytesName = analyte.Name;
                result.ResultModel = analyte.ResultModel;
                result.RoundingOff = analyte.RoundingOff;
                result.Units = analyte.Units;
                result.FUnits = analyte.FUnits;
                result.Assist = analyte.Assist;
                result.RetestNo = 0;
                result.Sort = 0;
                result.DetectionTimes = i;

                result.MethodId = analyte.MethodId;
                result.MethodCode = analyte.MethodCode;
                result.DetectionLimit = analyte.DetectionLimit;
                result.Original = analyte.DefaultValue;
                result.AlternativeResults = analyte.AlternativeResults;
                result.CMA = analyte.CMA;
                result.CNAS = analyte.CNAS;
                result.EqType = analyte.EqType;

                result.TestId = TestId;
                result.TestName = TestName;
                if (MethodId != null) // 如果传入的方法ID不为空，则用传入的方法覆盖分析项中的设置。
                {
                    var method = SAMPLE.Method.getMethod(dbContext, MethodId);
                    result.MethodId = method.Id;
                    result.MethodCode = method.Code;
                }
                result.TestTimes = TestTimes;
                
                if (!string.IsNullOrEmpty(TestId))
                    result.CalculationRules = dbContext.TestRelation
                        .FirstOrDefault(s => s.TestDefinitionId == TestId && s.AnalytesId == analyte.Id).CalculationRules;

                if (spec != null)
                {
                    result.LowA = spec.LowA;
                    result.HighA = spec.HighA;
                    result.StandardValue = spec.StandardValue;
                    result.LowB = spec.LowB;
                    result.HighB = spec.HighB;
                    result.AcceptanceCriteria = spec.AcceptanceCriteria;
                    result.AcceptanceRules = spec.AcceptanceRules;
                }

                dbContext.Add(result);
            }
        }

        /// <summary>
        /// 返回所需使用的样品编号数组。如果后续程序出错，该数组的样品编号即废弃。再次登录样品时，会按顺序继续取用新的编号。
        /// </summary>
        /// <param name="number"></param>
        /// <param name="SampleNumberArrary"></param>
        /// <returns></returns>
        private static string getSampleNumberArrary(CoreLimsContext dbContext, int number, out string[] SampleNumberArrary)
        {
            SampleNumberArrary = new string[number];
            var NumberBit = int.Parse(Common.getGlobalKeyValue(dbContext, "SampleNumber_Bit"));
            var NumberMax = int.Parse(Common.getGlobalKeyValue(dbContext, "SampleNumber_Max"));
            var NumberHead = Common.getGlobalKeyValue(dbContext, "SampleNumber_Head");
            string DateString = GetDateString();

            if (NumberHead != DateString) // 日期不相等则重新编号
            {
                Common.setGlobalKeyValue(dbContext, "SampleNumber_Head", DateString);
                NumberHead = DateString;
                NumberMax = 0;
            }

            var newMax = NumberMax + number;
            if (newMax.ToString().Length > NumberBit)
                return "样品编号数字部分已超出设定的最大值，请联系管理员！";
            else
                Common.setGlobalKeyValue(dbContext, "SampleNumber_Max", newMax.ToString());

            for (int i = 1; i <= number; i++)
            {
                var newNumber = getNewSampleNumber(NumberBit, NumberHead, NumberMax + i);
                SampleNumberArrary[i - 1] = newNumber;
            }

            return "成功";
        }

        /// <summary>
        /// 返回当前日期字符串
        /// </summary>
        /// <returns></returns>
        private static string GetDateString()
        {
            var date = DateTime.Now;
            var month = date.Month > 9 ? date.Month.ToString() : "0" + date.Month.ToString();
            var day = date.Day > 9 ? date.Day.ToString() : "0" + date.Day.ToString();
            var NumberHead = date.Year.ToString() + month + day;
            return NumberHead;
        }

        /// <summary>
        /// 根据传入的数值，返回样品编号
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        private static string getNewSampleNumber(int NumberBit, string NumberHead, int number)
        {
            int xbit = NumberBit - number.ToString().Length; // 计算出需要补几个0
            StringBuilder zero = new StringBuilder(NumberHead);

            for (int i = 1; i <= xbit; i++)
                zero.Append("0");
            zero.Append(number.ToString());

            return zero.ToString();
        }

        private static string StartCheck(CoreLimsContext dbContext, Sample sp, List<SampleLoginRelation> allList)
        {
            if (!CheckSpecCollection(allList))
                return "样品 " + sp.Name + " 包含有指标集，但没有设置默认指标集！";

            if (!CheckTestSpecCollection(allList))
                return "样品 " + sp.Name + " 关联的测试，没有设置默认指标集！";

            if (!CheckTestMethod(allList))
                return "样品 " + sp.Name + " 关联的测试，没有设置默认方法！";

            if (!CheckTestAnalytes(allList))
                return "样品 " + sp.Name + " 关联的测试，没有分析项！";

            if (!CheckAnalytes(allList))
                return "样品 " + sp.Name + " 没有包含分析项！";

            return null;
        }

        /// <summary>
        /// 检查样品是否包含指标集，如果包含指标集则必须要有默认指标集
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        private static bool CheckSpecCollection(List<SampleLoginRelation> list)
        {
            bool pass = true;
            var specList = list.Where(s => s.TestId == null && s.SpecCollectionId != null).ToList();

            if (specList.Count > 0)
            {
                var isList = list.Where(s => s.TestId == null && s.SpecCollectionId != null && s.IsDefault == true).ToList();
                if (isList.Count == 0)
                    pass = false;
            }

            return pass;
        }

        /// <summary>
        /// 检查测试是否包含指标集，如果包含指标集则必须要有默认指标集
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        private static bool CheckTestSpecCollection(List<SampleLoginRelation> list)
        {
            bool pass = true;
            var testList = list.Where(s => s.AnalyteId == null
                           && s.SpecCollectionId == null && s.MethodId == null).ToList();

            foreach (var item in testList)
            {
                var specList = list.Where(s => s.AnalyteId == null
                               && s.TestId == item.TestId && s.SpecCollectionId != null && s.MethodId == null).ToList();
                if (specList.Count > 0)
                {
                    var specIsList = list.Where(s => s.AnalyteId == null
                                       && s.TestId == item.TestId && s.SpecCollectionId != null
                                       && s.MethodId == null && s.IsDefault == true).ToList();
                    if (specIsList.Count == 0)
                    {
                        pass = false;
                        break;
                    }
                }
            }

            return pass;
        }

        /// <summary>
        /// 检查测试是否包含方法，如果包含方法则必须要有默认方法
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        private static bool CheckTestMethod(List<SampleLoginRelation> list)
        {
            bool pass = true;
            var testList = list.Where(s => s.AnalyteId == null
                           && s.SpecCollectionId == null && s.MethodId == null).ToList();

            foreach (var item in testList)
            {
                var methodList = list.Where(s => s.AnalyteId == null
                               && s.TestId == item.TestId && s.SpecCollectionId == null && s.MethodId != null).ToList();
                if (methodList.Count > 0)
                {
                    var methodIsList = list.Where(s => s.AnalyteId == null
                                       && s.TestId == item.TestId && s.SpecCollectionId == null
                                       && s.MethodId != null && s.IsDefault == true).ToList();
                    if (methodIsList.Count == 0)
                    {
                        pass = false;
                        break;
                    }
                }
            }

            return pass;
        }

        /// <summary>
        /// 检查测试是否包含分析项
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        private static bool CheckTestAnalytes(List<SampleLoginRelation> list)
        {
            bool pass = true;
            var testList = list.Where(s => s.AnalyteId == null
                           && s.SpecCollectionId == null && s.MethodId == null).ToList();

            foreach (var item in testList)
            {
                var anaList = list.Where(s => s.AnalyteId != null
                               && s.TestId == item.TestId && s.SpecCollectionId == null && s.MethodId == null)
                                .ToList().Count;

                if (anaList == 0)
                    pass = false;
            }

            return pass;
        }

        /// <summary>
        /// 登录样品至少包含一项分析项
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        private static bool CheckAnalytes(List<SampleLoginRelation> list)
        {
            bool pass = true;
            var anaList = list.Where(s => s.AnalyteId != null).ToList().Count;

            if (anaList == 0)
                pass = false;

            return pass;
        }

        /// <summary>
        /// 在“登录”样品关系中查找是否存在指定的分析项，如果存在返回第一个关联的样品名称
        /// </summary>
        /// <param name="AnalyteId"></param>
        /// <returns></returns>
        public static string CheckHasAnalyte(this Sample sp, CoreLimsContext dbContext, string AnalyteId)
        {
            string st = null;
            var list = from sample in dbContext.Sample
                       join login in dbContext.LoginRelation on sample.Id equals login.SampleId
                       where (sample.Status == "登录" && login.AnalyteId == AnalyteId)
                       select sample;

            if (list.Count() > 0)
                st = list.FirstOrDefault().Name;

            return st;
        }

        /// <summary>
        /// 在所有“登录”和“检测中”的样品里查找指定方法的引用，如果存在返回第一个关联的样品名称
        /// </summary>
        /// <param name="sp"></param>
        /// <param name="dbContext"></param>
        /// <param name="MethodId"></param>
        /// <returns></returns>
        public static string CheckHasMethod(this Sample sp, CoreLimsContext dbContext, string MethodId)
        {
            string st = null;
            var list = from sample in dbContext.Sample
                       join login in dbContext.LoginRelation on sample.Id equals login.SampleId
                       where (sample.Status == "登录" && sample.Status == "检测中" && login.MethodId == MethodId)
                       select sample;

            if (list.Count() > 0)
                st = list.FirstOrDefault().Name;

            return st;
        }

        /// <summary>
        /// 在“登录”样品关系中查找是否存在指定的指标集，如果存在返回第一个关联的样品名称
        /// </summary>
        /// <param name="sp"></param>
        /// <param name="dbContext"></param>
        /// <param name="SpecCollectionId"></param>
        /// <returns></returns>
        public static string CheckHasSpecCollection(this Sample sp, CoreLimsContext dbContext, string SpecCollectionId)
        {
            string st = null;
            var list = from sample in dbContext.Sample
                       join login in dbContext.LoginRelation on sample.Id equals login.SampleId
                       where (sample.Status == "登录" && login.SpecCollectionId == SpecCollectionId)
                       select sample;

            if (list.Count() > 0)
                st = list.FirstOrDefault().Name;

            return st;
        }

        /// <summary>
        /// 采样操作
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids"></param>
        /// <returns></returns>
        public static string Sampling(this Sample sample, CoreLimsContext dbContext, string Ids, string userID, string userName)
        {
            if (string.IsNullOrEmpty(Ids))
                return "请先选择需要采样的样品";

            var list = dbContext.Sample.Where(s => Ids.Contains(s.Id)).ToList();
            foreach (var sp in list)
            {
                SAMPLE.RunWorkflow(dbContext, sp, userID, userName);
            }

            dbContext.SaveChanges();
            return "样品采集成功！";
        }

        /// <summary>
        /// 生成采样标签，并返回生成的文件名
        /// </summary>
        /// <param name="Sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string CreateSamplingLab(this Sample Sample, CoreLimsContext dbContext, string Ids, string fileName)
        {
            var dir = Common.getGlobalKeyValue(dbContext, "SamplingLab_Path");
            var dirfileName = dir + "\\" + fileName; // "采样标签.docx";

            var list = from sample in dbContext.Sample
                       join runtime in dbContext.RuntimeWorkFlow on sample.Id equals runtime.DomainId
                       join setp in dbContext.RuntimeStepSequence on runtime.Id equals setp.RuntimeWorkFlowId
                       where (Ids.Contains(sample.Id) && setp.StepName == "采样")
                       select new
                       {
                           sample.SampleId,
                           sample.Classification,
                           sample.GenricClass,
                           sample.Name,
                           setp.HandlingTime,
                           setp.CurrentHandlerId
                       };
            try
            {
                var fileID = Common.Report.CreateSamplingLabel(list, dirfileName, dir);
                return fileID;
            }
            catch (Exception ex)
            {
                var audit = Audit.newAudit;
                audit.EventName = "打印标签";
                audit.TableName = "标签名称：" + fileName;
                audit.Explain = ex.Message.Substring(0, ex.Message.Length > 1000 ? 1000 : ex.Message.Length); ;
                dbContext.Add(audit);
                dbContext.SaveChanges();
            }
            return null;
        }

        /// <summary>
        /// 打印样品标签，这个标签跟样品流程无关
        /// </summary>
        /// <param name="Sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string CreateSampleLab(this Sample Sample, CoreLimsContext dbContext, string Ids, string fileName)
        {
            var dir = Common.getGlobalKeyValue(dbContext, "SamplingLab_Path");
            var dirfileName = dir + "\\" + fileName; // "采样标签.docx";

            var list = Sample.getSampleList(dbContext).Where(s => Ids.Contains(s.Id)).ToList();

            try
            {
                var fileID = Common.Report.CreateSampleLabel(list, dirfileName, dir);
                return fileID;
            }
            catch (Exception ex)
            {
                var audit = Audit.newAudit;
                audit.EventName = "打印标签";
                audit.TableName = "标签名称：" + fileName;
                audit.Explain = ex.Message.Substring(0, ex.Message.Length > 1000 ? 1000 : ex.Message.Length); ;
                dbContext.Add(audit);
                dbContext.SaveChanges();
            }
            return null;
        }

        /// <summary>
        /// 样品信息导出到EXCEL文件
        /// </summary>
        /// <param name="Sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids"></param>
        /// <returns></returns>
        public static string SampleToExcel(this Sample Sample, CoreLimsContext dbContext, string Ids)
        {
            var fileName = Common.getGlobalKeyValue(dbContext, "ExportSampleExcel_Path");
            var list = Sample.getSampleList(dbContext).Where(s => Ids.Contains(s.Id)).ToList();

            try
            {
                var fileID = Common.Report.SampleToExcel(list, fileName);
                return fileID;
            }
            catch (Exception ex)
            {
                var audit = Audit.newAudit;
                audit.EventName = "样品导出";
                audit.TableName = "文件名：" + fileName;
                audit.Explain = ex.Message.Substring(0, ex.Message.Length > 1000 ? 1000 : ex.Message.Length); ;
                dbContext.Add(audit);
                dbContext.SaveChanges();
            }
            return null;
        }

        /// <summary>
        /// 样品接收操作
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids"></param>
        /// <returns></returns>
        public static string ReceiveSamples(this Sample sample, CoreLimsContext dbContext, string Ids, string userID, string userName)
        {
            if (string.IsNullOrEmpty(Ids))
                return "请先选择需要接收的样品";

            var list = dbContext.Sample.Where(s => Ids.Contains(s.Id)).ToList();
            foreach (var sp in list)
            {
                SAMPLE.RunWorkflow(dbContext, sp, userID, userName);
            }

            dbContext.SaveChanges();
            return "样品接收成功！";
        }

        /// <summary>
        /// 样品审核全部使用这个函数
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids"></param>
        /// <returns></returns>
        public async static Task<string> ExamineAndVerify(this Sample sample, CoreLimsContext dbContext, string Ids, string userID, string userName)
        {
            if (string.IsNullOrEmpty(Ids))
                return "请先选择需要审核的样品";

            var list = dbContext.Sample.Where(s => Ids.Contains(s.Id)).ToList();
            foreach (var sp in list)
            {
                SAMPLE.RunWorkflow(dbContext, sp, userID, userName);
            }

            await dbContext.SaveChangesAsync();
            return "样品审核完成！";
        }

        /// <summary>
        /// 废弃指定样品
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="Ids"></param>
        /// <param name="userID"></param>
        /// <param name="userName"></param>
        /// <param name="Suggestion">废弃样品的原因</param>
        /// <returns></returns>
        public static string DoAbandon(this Sample sample, CoreLimsContext dbContext, string SampleIds, CommonUser user, string Suggestion)
        {
            if (string.IsNullOrEmpty(SampleIds))
                return "请先选择需要废弃的样品";

            var list = SampleIds.Split(',');
            foreach (var id in list)
            {
                var sp = SAMPLE.Sample.getSampleLogin(dbContext, id);
                if (sp.Status != "废弃")
                {
                    SAMPLE.DoEndStep(dbContext, sp, user, Suggestion);
                    sp.Status = SAMPLE.SampleStatus.废弃.ToString();
                    sp.CurrentWorkFlow = "结束";
                    sp.NextWorkFlow = null;
                    dbContext.Update(sp);
                }
            }

            dbContext.SaveChanges();

            return "选择样品已废弃！";
        }

        /// <summary>
        /// 生成单样品报告
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="SampleId">样品ID</param>
        /// <param name="fileName">报告模板名称</param>
        /// <returns></returns>
        public static string CreateSingleReport(this Sample Sample, CoreLimsContext dbContext, string SampleId, string fileName) // 需要用户
        {
            var dir = Common.getGlobalKeyValue(dbContext, "ReportTemplate_Path");
            var dirfileName = dir + "\\" + fileName;

            var list = from sample in dbContext.Sample
                       join result in dbContext.Result on sample.Id equals result.SampleId
                       where sample.Id == SampleId && result.Assist == false
                       select new
                       {
                           sample.Id, sample.SampleId, result.AcceptanceCriteria, result.AnalytesCode,
                           result.AnalytesName,result.Final, result.Units, result.Conclusion
                       };

            var saveDir = Common.UploadFile.getPath(dbContext, "Sample", SampleId) + "\\";
            var fileID = CreateReport.Common.CreateSingleReport(list, dirfileName, saveDir, out string fileSize);

            CommonUploadFile uf = new CommonUploadFile();
            uf.Id = fileID; // 覆盖自动生成的ID
            uf.UploadTime = DateTime.Now;
            uf.Domain = "Sample";
            uf.DomainId = SampleId;
            uf.FileName = fileName;
            uf.FileType = "docx";
            uf.FileSize = fileSize;
            uf.CreateById = "1";
            uf.CreateByName = "SYSADM";
            dbContext.Add(uf);
            dbContext.SaveChanges();

            return "生成报告成功！";
        }

        /// <summary>
        /// 生成批量样品报告
        /// </summary>
        /// <param name="Sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="SampleId"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string CreatMultiReport(this Sample Sample, CoreLimsContext dbContext, string SampleId, string fileName) // 需要用户
        {
            //var dir = Common.getGlobalKeyValue(dbContext, "ReportTemplate_Path");
            //var dirfileName = dir + "\\" + fileName;

            //var list = from sample in dbContext.Sample
            //           join result in dbContext.Result on sample.Id equals result.SampleId
            //           where sample.Id == SampleId && result.Assist == false
            //           select new
            //           {
            //               sample.Id,
            //               sample.SampleId,
            //               result.AcceptanceCriteria,
            //               result.AnalytesCode,
            //               result.AnalytesName,
            //               result.Final,
            //               result.Units,
            //               result.Conclusion
            //           };

            //var saveDir = Common.UploadFile.getPath(dbContext, "Sample", SampleId) + "\\";
            var fileID = CreateReport.Common.CreatMultiReport(); // list, dirfileName, saveDir, out string fileSize

            //CommonUploadFile uf = new CommonUploadFile();
            //uf.Id = fileID; // 覆盖自动生成的ID
            //uf.UploadTime = DateTime.Now;
            //uf.Domain = "Sample";
            //uf.DomainId = SampleId;
            //uf.FileName = fileName;
            //uf.FileType = "docx";
            //uf.FileSize = fileSize;
            //uf.CreateById = "1";
            //uf.CreateByName = "SYSADM";
            //dbContext.Add(uf);
            //dbContext.SaveChanges();

            return fileID;
        }

        /// <summary>
        /// 将样品定义添加到样品组中
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="SampleDefinitionList"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public static string AddSampleToSampleGroup(this Sample sample, CoreLimsContext dbContext, string SampleDefinitionList, CommonUser user, string SampleGroupId)
        {
            var sdList = SampleDefinitionList.Split(',');
            string SampleDefinitionId = "";
            string SampleDefinitionName = "";

            try
            {
                foreach (var item in sdList)
                {
                    SampleDefinitionId = item.Split('.')[0];
                    var number = 1;
                    int.TryParse(item.Split('.')[1], out number);

                    var sd = SAMPLE.SampleDefinition.getSampleDefinition(dbContext, SampleDefinitionId); // 获得 样品定义
                    var sg = new SampleSampleGroup();
                    sg.SampleGroupId = SampleGroupId;
                    sg.SampleId = sd.Id;
                    sg.Site = sd.Site;
                    sg.Group = sd.Group;
                    sg.SampleNumber = number;
                    dbContext.SampleGroup.Add(sg);
                }

                dbContext.SaveChanges();
                return "样品添加成功！";
            }
            catch (Exception ex)
            {
                var audit = Audit.newAudit;
                audit.EventName = "添加样品到样品组";
                audit.TableName = "样品名称：" + SampleDefinitionName;
                audit.RecordId = SampleDefinitionId;
                audit.RemindUserId = user.Id;
                audit.RemindUserName = user.FullName;
                audit.Explain = ex.Message.Substring(0, ex.Message.Length > 1000 ? 1000 : ex.Message.Length); ;
                dbContext.Add(audit);
                dbContext.SaveChanges();

                return "样品添加失败！该信息已被系统记录，请联系管理员。";
            }
        }

        /// <summary>
        /// 根据 EXCEL 文件内容，更新 Sample 表
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="dbContext"></param>
        /// <param name="fileID"></param>
        /// <returns></returns>
        public static string ExcelToSample(this Sample sample, CoreLimsContext dbContext, string fileID)
        {
            using (FileStream ps = new FileStream(fileID, FileMode.Open, FileAccess.ReadWrite))
            {
                XSSFWorkbook workbook = new XSSFWorkbook(ps);
                ISheet sheet = workbook.GetSheetAt(0);
                int a = 1;
                while (a > 0)
                {
                    IRow row = sheet.GetRow(a);
                    if (row != null)
                    {
                        try
                        {
                            var sp = SAMPLE.Sample.getSampleLogin(dbContext, row.GetCell(0).StringCellValue);
                            sp.SampleNumber = row.GetCell(2).ToString();
                            sp.BatchId = row.GetCell(3).ToString();
                            dbContext.Sample.Update(sp);
                            dbContext.SaveChanges();
                            a++;
                        }
                        catch (Exception ex)
                        {
                            return row.GetCell(1).StringCellValue + ex.Message;
                        }
                    }
                    else
                        return "导入成功！";
                }

            }
            return "导入数据错误，请联系管理员！";
        }

    }

}
